#!/bin/bash

include "git.sh"
include "objectv5.sh"
include "test.sh"

ObjectV5::DefineClass Updater "
    --proxy
    --cargs=gitpath
    --string=gitpath
    --string=new,false
    --string=version
"

function Updater::IsNew()
{
    [ $# == 0 ] && assert_fail "this"
    local this="$1"; shift
    [ "$(Updater::new "$this")" == "true" ]
    return
}

function Updater::IsValid()
{
    [ $# == 0 ] && assert_fail "this"
    local this="$1"; shift
    local gitpath="$(Updater::gitpath "$this")"
    Git git{"$gitpath"}
    Git::IsValid git
    return
}

function Updater::CheckBranch()
{
    [ $# == 0 ] && assert_fail "this"
    local this="$1"; shift
    local branch_regex="$1"; shift
    local gitpath="$(Updater::gitpath "$this")"
    Git git{"$gitpath"}
    [[ "$(Git::GetBranchName git HEAD)" =~ (^$branch_regex$) ]]
    return
}

function Updater::CheckModify()
{
    [ $# == 0 ] && assert_fail "this"
    local this="$1"; shift
    local gitpath="$(Updater::gitpath "$this")"
    Git git{"$gitpath"}
    Git::IsModified git
    return
}

function Updater::Update()
{
    [ $# == 0 ] && assert_fail "this"
    local this="$1"; shift
    local gitpath="$(Updater::gitpath "$this")"
    local upstream_position="$1"; shift
    Git git{"$gitpath"}
    Git::MoveTo git "$upstream_position" || return
    Git::SubmoduleUpdate git || return
    Updater::new "$this" false
    Updater::version "$this" "$(Git::GetHash git "$upstream_position")"
    return
}

function Updater::Fetch()
{
    [ $# == 0 ] && assert_fail "this"
    local this="$1"; shift
    local remote="${1:-origin}"; shift
    local branch="${1:-master}"; shift
    local gitpath="$(Updater::gitpath "$this")"
    local old_version="$(Updater::version "$this")"
    Git git{"$gitpath"}
    if slient Git::Fetch git "$remote"; then
        local new_version="$(Git::GetHash git "$branch")"
        if [ "$new_version" != "$old_version" ]; then
            Updater::new "$this" true
        fi
    fi
    return
}

function Updater::Test1()
{
    local testgit1="$(test::get_temp_path git.test1)"
    local testgit2="$(test::get_temp_path git.test1)"
    local testgit3="$(test::get_temp_path git.test1)"

    function Updater::Test1::BeforeTest()
    {
        # 1. init
        mkdir "$testgit1"
        cd "$testgit1"
        git init --bare

        # 2. push 2commits at 1
        git clone "file://${testgit1}" "$testgit2"
        cd "$testgit2"
        echo 1 > 1
        git add .
        git commit -m "1"
        git branch 1
        echo 2 > 2
        git add .
        git commit -m "2"
        git push origin master

        # 3. create branch dev
        git branch dev

        # 4. clone at 2
        git clone "file://${testgit1}" "$testgit3"

        # 5. push 1more commit at 1
        cd "$testgit2"
        echo 3 > 1
        git add .
        git commit -m "3"
        git push origin master

        # 6. goto home
        cd
    }

    function Updater::Test1::AfterTest()
    {
        rm -rf "$testgit1"
        rm -rf "$testgit2"
        rm -rf "$testgit3"
    }

    Git git1{"$testgit2"}
    Git git2{"$testgit3"}
    Updater updater{"$testgit3"}

    # IsValid
    test::should_return_false Updater::IsValid updater
    slient                    Updater::Test1::BeforeTest
    test::should_return_true  Updater::IsValid updater

    local hash1="$(Git::GetHash git1 1)"
    local hash2="$(Git::GetHash git1 dev)"
    local hash3="$(Git::GetHash git1 master)"

    test::should_return_false Updater::IsNew       updater
    test::should_return_true  Updater::CheckBranch updater master
    test::should_return_false Updater::CheckBranch updater dev
    test::should_return_false Updater::CheckModify updater

    slient                    cd "$testgit3"
                              echo 3 > 3
    test::should_return_false Updater::CheckModify updater
                              echo 4 > 1
    test::should_return_true  Updater::CheckModify updater
                              git checkout -- 1

    slient                    Updater::Fetch       updater
    test::should_return_true  Updater::IsNew       updater
    test::run_cmd             Updater::version     updater
    test::should_be           ""

    slient                    Updater::Update      updater origin/master
    test::should_return_false Updater::IsNew       updater
    test::run_cmd             Updater::version     updater
    test::should_be           "${hash3}"

    slient                    Updater::Test1::AfterTest
    return
}
test::register_test Updater::Test1
